package com.prime.beans;

import com.prime.component.ComboBox;
import com.prime.component.Component;
import com.prime.component.ComponentType;
import com.prime.component.TextField;
import com.prime.modelo.Prime;
import com.prime.modelo.ServicioBase;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.inject.Inject;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.primefaces.event.DragDropEvent;
import org.w3c.dom.*;

/**
 *
 * @author wporras
 */
@ManagedBean
@SessionScoped
public class BeanDraggable implements Serializable {

    @Inject
    ServicioBase servicioBase;
    private List<Component> panelTools;
    private List<Component> workArea;
    private Document doc;
    private Element bodyElement;
    private String title;
    private String table;
    private String labelBotton;
    private String labelFielSet;

    public BeanDraggable() {
        panelTools = new ArrayList<Component>();
        workArea = new ArrayList<Component>();
        panelTools.add(new TextField("textField"));
        panelTools.add(new ComboBox("comboBox"));
        title = "";
        table = "";
        labelBotton = "Next";
        labelFielSet = "Form Creator";
    }

    public void onComponentDrop(DragDropEvent event) {
        Component component = null;
        try {
            component = ((Component) event.getData()).clone();
        } catch (CloneNotSupportedException ex) {
            Logger.getLogger(BeanDraggable.class.getName()).log(Level.SEVERE, null, ex);
        }
        getWorkArea().add(component);
    }

    public void nextForm() {
        if (labelBotton.equals("Next")) {
            crearXMLRoot();
            crearXMLFormCreator();
            DomToString(false);
            labelBotton = "Save";
            setLabelFielSet("Form Appover");            

        } else {
            crearXMLFormApprover();
            DomToString(true);
            
            labelBotton = "Next";
            setLabelFielSet("Form Creator");
            table = "";
            title = "";
            workArea.clear();            
        }
    }

    private void crearXMLFormCreator() {
        //form element
        Element formElement = getDoc().createElement("cr:form");
        getBodyElement().appendChild(formElement);

        //panel element
        Element panelElement = getDoc().createElement("cr:panel");
        formElement.appendChild(panelElement);

        //set attribute title to panel element
        Attr attrTitle = getDoc().createAttribute("title");
        attrTitle.setValue(getTitle());
        panelElement.setAttributeNode(attrTitle);

        //set attribute role to panel element
        Attr attrRole = getDoc().createAttribute("role");
        attrRole.setValue("employed");
        panelElement.setAttributeNode(attrRole);

        //set attribute typeForm to panel element
        Attr attrTypeForm = getDoc().createAttribute("typeForm");
        attrTypeForm.setValue("creator");
        panelElement.setAttributeNode(attrTypeForm);

        //set attribute tableReference to panel element
        Attr attrTableReference = getDoc().createAttribute("tableReference");
        attrTableReference.setValue(getTable());
        panelElement.setAttributeNode(attrTableReference);

        //Para cada componente
        for (Component component : getWorkArea()) {
            if (component.getType().equals(ComponentType.TEXT_FIELD)) {
                panelElement.appendChild(crearXmlTextField(component));
            } else {
                panelElement.appendChild(crearXmlComboBox(component));
            }
        }
    }

    private void crearXMLFormApprover() {
        //form element
        Element formElement = getDoc().createElement("cr:form");
        getBodyElement().appendChild(formElement);

        //panel element
        Element panelElement = getDoc().createElement("cr:panel");
        formElement.appendChild(panelElement);

        //set attribute title to panel element
        Attr attrTitle = getDoc().createAttribute("title");
        attrTitle.setValue(getTitle());
        panelElement.setAttributeNode(attrTitle);

        //set attribute role to panel element
        Attr attrRole = getDoc().createAttribute("role");
        attrRole.setValue("manager");
        panelElement.setAttributeNode(attrRole);

        //set attribute typeForm to panel element
        Attr attrTypeForm = getDoc().createAttribute("typeForm");
        attrTypeForm.setValue("approver");
        panelElement.setAttributeNode(attrTypeForm);

        //set attribute tableReference to panel element
        Attr attrTableReference = getDoc().createAttribute("tableReference");
        attrTableReference.setValue(getTable());
        panelElement.setAttributeNode(attrTableReference);

        //Para cada componente
        for (Component component : getWorkArea()) {
            if (component.getType().equals(ComponentType.TEXT_FIELD)) {
                panelElement.appendChild(crearXmlTextField(component));
            } else {
                panelElement.appendChild(crearXmlComboBox(component));
            }
        }
    }

    private void crearXMLRoot() {
        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            DOMImplementation domImpl = docBuilder.getDOMImplementation();

            //root element
            setDoc(domImpl.createDocument("http://www.primefaces.com", "cr:project", null));

            //body element
            setBodyElement(getDoc().createElement("cr:body"));
            getDoc().getDocumentElement().appendChild(getBodyElement());
        } catch (ParserConfigurationException pce) {
            pce.printStackTrace();
        }
    }

    public String DomToString(Boolean salvar) {
        String xml = "";
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            StringWriter writer = new StringWriter();
            transformer.transform(new DOMSource(getDoc()), new StreamResult(writer));
            //String output = writer.getBuffer().toString().replaceAll("\n|\r", "");
            xml = writer.getBuffer().toString();
            
            
            if (salvar) {
                Prime prime = new Prime();
                prime.setDescription(title);
                prime.setPrime(xml.getBytes());
                servicioBase.guardar(prime);            
            }
            
            System.out.println(xml);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return xml;
    }

    private Node crearXmlTextField(Component component) {
        //element
        Element element = getDoc().createElement("cr:textField");

        //set atribute tableReference to element
        Attr attrTableReference = getDoc().createAttribute("tableReference");
        attrTableReference.setValue(table);
        element.setAttributeNode(attrTableReference);
        
        //set atribute type to element
        Attr attrType = getDoc().createAttribute("type");
        attrType.setValue(component.getFormatType());
        element.setAttributeNode(attrType);
        
        //set atribute edit to element
        Attr attrEdit = getDoc().createAttribute("edit");
        attrEdit.setValue(component.getEdit());
        element.setAttributeNode(attrEdit);
        
        //set atribute columnReference to element
        Attr attrColumnReference = getDoc().createAttribute("columnReference");
        attrColumnReference.setValue(component.getColumnReference());
        element.setAttributeNode(attrColumnReference);

        //set atribute value to element
        Attr attrValue = getDoc().createAttribute("value");
        attrValue.setValue("");
        element.setAttributeNode(attrValue);

        //set atribute name to element
        Attr attrName = getDoc().createAttribute("label");
        attrName.setValue(component.getName());
        element.setAttributeNode(attrName);

        return element;
    }

    private Node crearXmlComboBox(Component component) {
        //element
        Element element = getDoc().createElement("cr:comboBox");

        //set atribute tableReference to element
        Attr attrTableReference = getDoc().createAttribute("tableReference");
        attrTableReference.setValue(component.getChilTable());
        element.setAttributeNode(attrTableReference);
        
        //set atribute edit to element
        Attr attrEdit = getDoc().createAttribute("edit");
        attrEdit.setValue(component.getEdit());
        element.setAttributeNode(attrEdit);

        //set atribute value to element
        Attr attrValue = getDoc().createAttribute("value");
        attrValue.setValue("");
        element.setAttributeNode(attrValue);

        //set atribute name to element
        Attr attrName = getDoc().createAttribute("label");
        attrName.setValue(component.getName());
        element.setAttributeNode(attrName);

        //element option
        Element elementOption = getDoc().createElement("cr:options");

        //set atribute type to SubElement
        Attr attrType = getDoc().createAttribute("type");
        attrType.setValue(component.getFormatType());
        elementOption.setAttributeNode(attrType);  
        
        //set atribute value to SubElement
        Attr attrOptionValue = getDoc().createAttribute("value");
        attrOptionValue.setValue(component.getColumnReference());
        elementOption.setAttributeNode(attrOptionValue);   
        
        //set atribute label to SubElement
        Attr attrOptionLabel = getDoc().createAttribute("label");
        attrOptionLabel.setValue(component.getColumnLabel());
        elementOption.setAttributeNode(attrOptionLabel);   
                               
        element.appendChild(elementOption);

        return element;
    }

    /**
     * @return the panelTools
     */
    public List<Component> getPanelTools() {
        return panelTools;
    }

    /**
     * @param panelTools the panelTools to set
     */
    public void setPanelTools(List<Component> panelTools) {
        this.setPanelTools(panelTools);
    }

    /**
     * @return the workArea
     */
    public List<Component> getWorkArea() {
        return workArea;
    }

    /**
     * @param workArea the workArea to set
     */
    public void setWorkArea(List<Component> workArea) {
        this.setWorkArea(workArea);
    }

    /**
     * @return the doc
     */
    public Document getDoc() {
        return doc;
    }

    /**
     * @param doc the doc to set
     */
    public void setDoc(Document doc) {
        this.doc = doc;
    }

    /**
     * @return the bodyElement
     */
    public Element getBodyElement() {
        return bodyElement;
    }

    /**
     * @param bodyElement the bodyElement to set
     */
    public void setBodyElement(Element bodyElement) {
        this.bodyElement = bodyElement;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * @return the table
     */
    public String getTable() {
        return table;
    }

    /**
     * @param table the table to set
     */
    public void setTable(String table) {
        this.table = table;
    }

    /**
     * @return the labelBotton
     */
    public String getLabelBotton() {
        return labelBotton;
    }

    /**
     * @param labelBotton the labelBotton to set
     */
    public void setLabelBotton(String labelBotton) {
        this.labelBotton = labelBotton;
    }

    /**
     * @return the labelFielSet
     */
    public String getLabelFielSet() {
        return labelFielSet;
    }

    /**
     * @param labelFielSet the labelFielSet to set
     */
    public void setLabelFielSet(String labelFielSet) {
        this.labelFielSet = labelFielSet;
    }
}
